{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "\n",
    "load_dotenv()\n",
    "\n",
    "llm = ChatOpenAI(model=\"qwen-max\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 单轮提示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三原色是指能够通过不同比例的混合生成其他颜色的基础颜色。根据应用领域的不同，三原色可以分为加法三原色和减法三原色两大类：\n",
      "\n",
      "1. **加法三原色**：主要应用于发光体的颜色混合，如电视、电脑屏幕等显示设备。加法三原色指的是红（Red）、绿（Green）、蓝（Blue），简称RGB。这三种颜色以不同强度组合可以产生各种色彩。\n",
      "\n",
      "2. **减法三原色**：主要用于颜料或染料的颜色混合，比如印刷业中使用的油墨。减法三原色指的是青（Cyan）、品红（Magenta）以及黄（Yellow），有时也会加上黑色（Black）来增强对比度和深度，这就是CMYK色彩模型的基础。\n",
      "\n",
      "在日常交流中如果不特别指明领域，默认情况下提到的“三原色”通常是指加法三原色即红、绿、蓝(RGB)。\n"
     ]
    }
   ],
   "source": [
    "single_turn_prompt = \"三原色是哪三种颜色？\"\n",
    "\n",
    "print(llm.invoke(single_turn_prompt).content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "颜色的原理主要基于光与物质相互作用以及人眼对这种相互作用结果的感受。当光源发出的光线照射到物体上时，物体会吸收某些波长（颜色）的光，并反射或透射其他波长的光。我们看到的颜色实际上是物体反射或透射出来的光的颜色。例如，如果一个物体看起来是红色的，那是因为它反射了红光而吸收了其他颜色的光。\n",
      "\n",
      "在色彩理论中，颜色有三个主要组成部分，通常被称为色彩三要素或颜色模型中的三个维度：\n",
      "\n",
      "1. **色相（Hue）**：指的是纯色的基本属性，也就是我们通常所说的“颜色”，如红色、蓝色等。它是根据光谱上的位置来定义的，反映了颜色的基本类型。\n",
      "2. **饱和度（Saturation）**：也称为纯度或彩度，描述的是颜色的纯净程度或鲜艳程度。饱和度越高，颜色看起来越纯正、越鲜艳；饱和度低则意味着颜色更加接近灰色调。\n",
      "3. **亮度（Brightness）或明度（Value）**：指颜色的明亮程度，即从黑色到白色之间的变化。对于给定的色相和饱和度，通过调整亮度可以得到不同深浅的效果。\n",
      "\n",
      "这三者共同决定了一个颜色的具体表现形式。不同的组合会产生无数种颜色变化，从而构成了丰富多彩的世界。此外，在不同的应用领域（如印刷、电子显示等），可能还会使用特定的颜色模型来表示这三个组成部分，比如RGB（红绿蓝）、CMYK（青品黄黑）等。\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "\n",
    "structured_prompt = PromptTemplate(\n",
    "    input_variables=[\"topic\"], template=\"简要说明{topic}并列出其三个主要组成部分。\"\n",
    ")\n",
    "\n",
    "chain = structured_prompt | llm\n",
    "print(chain.invoke({\"topic\": \"颜色的原理\"}).content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多轮提示（会话）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "from langgraph.graph import START, MessagesState, StateGraph\n",
    "\n",
    "\n",
    "# Define a new graph\n",
    "workflow = StateGraph(state_schema=MessagesState)\n",
    "\n",
    "\n",
    "# Define the function that calls the model\n",
    "def call_model(state: MessagesState):\n",
    "    response = llm.invoke(state[\"messages\"])\n",
    "    return {\"messages\": response}\n",
    "\n",
    "\n",
    "# Define the (single) node in the graph\n",
    "workflow.add_edge(START, \"model\")\n",
    "workflow.add_node(\"model\", call_model)\n",
    "\n",
    "# Add memory\n",
    "memory = MemorySaver()\n",
    "app = workflow.compile(checkpointer=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "当然可以！行星是围绕恒星（如我们的太阳）运行的天体，具有足够的质量以自身的重力克服刚体力，从而达到流体静力平衡（近似球形），并且已经清除了其轨道附近的其他物体。根据国际天文联合会2006年的定义，一颗行星必须满足以下三个条件：\n",
      "\n",
      "1. 绕着太阳公转。\n",
      "2. 有足够大的质量来克服固体应力，使其形状接近于流体静力平衡状态下的形状（通常是球形或略扁的球形）。\n",
      "3. 已经清空了它所在轨道上的区域，即在其轨道上没有其他大量小天体存在。\n",
      "\n",
      "在我们太阳系中，目前被正式认定为行星的一共有八颗，按照离太阳的距离从近到远依次为：水星、金星、地球、火星、木星、土星、天王星和海王星。这八大行星又可以根据它们的特点分为两大类：\n",
      "\n",
      "- **岩石行星**：包括水星、金星、地球和火星。这些行星主要由岩石或金属构成，体积相对较小，密度较高。\n",
      "- **气态巨行星**：包括木星、土星、天王星和海王星。这类行星拥有巨大的气体包层，主要是氢和氦组成的大气层，以及可能存在的液体内部结构。其中，天王星和海王星因为含有较多的冰物质（如水、氨和甲烷），有时也被称作“冰巨星”。\n",
      "\n",
      "此外，还有许多其他有趣的天体绕太阳运行，比如矮行星（例如冥王星）、小行星带中的小行星、柯伊伯带及奥尔特云中的彗星等，它们虽然不符合行星的标准定义，但也是太阳系内不可或缺的一部分。\n",
      "\n",
      "如果你对某个特定的行星或者关于行星探索的历史感兴趣的话，请告诉我，我很乐意提供更多相关信息！\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "我们的太阳系中最大的行星是木星。木星是一颗气态巨行星，其体积和质量都非常庞大。具体来说：\n",
      "\n",
      "- **体积**：木星的体积大约是地球的1,321倍。\n",
      "- **质量**：它的质量约为地球的318倍。\n",
      "- **直径**：木星的赤道直径约为139,820公里（约86,881英里），是太阳系中直径最大的行星。\n",
      "\n",
      "木星主要由氢和氦组成，拥有强大的磁场和至少79颗已知的卫星。其中最著名的四颗伽利略卫星分别是：伽利莫德、欧罗巴、甘尼米德和卡利斯托。此外，木星还以其独特的大红斑而闻名，这是一个已经持续存在了数百年的巨大风暴系统。\n",
      "\n",
      "由于其巨大的质量和引力影响，木星在太阳系的动力学结构中扮演着重要角色，对其他天体的轨道有着显著的影响。\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "与地球相比，木星的体积和质量都大得多。具体来说：\n",
      "\n",
      "- **体积**：木星的体积大约是地球的1,321倍。这意味着如果把地球想象成一个篮球，那么木星的大小就相当于一个巨大的热气球。\n",
      "\n",
      "- **质量**：木星的质量约为地球的318倍。尽管木星的质量如此之大，但由于其主要由氢和氦等轻元素组成，其平均密度却比地球低得多。地球的平均密度约为5.52克/立方厘米，而木星的平均密度仅为1.33克/立方厘米。\n",
      "\n",
      "- **直径**：木星的赤道直径约为139,820公里（约86,881英里），而地球的直径约为12,742公里（约7,918英里）。因此，木星的直径大约是地球的11倍。\n",
      "\n",
      "- **表面积**：木星的表面积约为地球的122倍。\n",
      "\n",
      "通过这些数据，你可以更直观地感受到木星的巨大。如果你站在地球上仰望夜空中的木星，很难想象它实际上有多么庞大。此外，木星的大红斑本身就是一个巨大的风暴系统，其直径甚至可以容纳两个地球。\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "\n",
    "\n",
    "config = {\"configurable\": {\"thread_id\": \"abc123\"}}\n",
    "\n",
    "multi_turn_prompts = [\n",
    "    \"你好，我正在学习太空知识。你能告诉我有关行星的知识吗？\",\n",
    "    \"我们的太阳系中最大的行星是什么？\",\n",
    "    \"与地球相比的话，它有多大？\",\n",
    "]\n",
    "\n",
    "for prompt in multi_turn_prompts:\n",
    "    input_messages = [HumanMessage(prompt)]\n",
    "    output = app.invoke({\"messages\": input_messages}, config)\n",
    "    # output contains all messages in state\n",
    "    output[\"messages\"][-1].pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 单轮 VS 多轮"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "单轮回复:\n",
      "Q: 法国首都在哪？\n",
      "A: 法国的首都是巴黎(Paris)。\n",
      "\n",
      "Q: 它有多少人口？\n",
      "A: 您的问题中没有提到具体的“它”是指哪个地方或国家，所以我无法直接给出答案。如果您能提供更详细的信息，比如具体的城市名、省份名或国家名，我就能帮助您找到相关的人口数据了。\n",
      "\n",
      "Q: 这个城市最著名的地标是什么？\n",
      "A: 您的问题中没有提到具体是哪个城市，不同的城市有着不同的著名地标。例如：\n",
      "\n",
      "- 如果您指的是北京，那么最著名的地标可能是天安门广场和故宫。\n",
      "- 对于上海来说，东方明珠塔是一个非常知名的地标。\n",
      "- 在巴黎，埃菲尔铁塔无疑是该市最标志性的建筑之一。\n",
      "- 纽约则以其自由女神像闻名于世。\n",
      "\n",
      "请告诉我您想了解哪个城市的地标，我将为您提供更详细的信息。\n",
      "\n",
      "多轮回复:\n",
      "Q: 法国首都在哪？\n",
      "A: 法国的首都是巴黎（Paris）。\n",
      "\n",
      "Q: 它有多少人口？\n",
      "A: 截至2021年的数据，巴黎市内的人口大约为216万左右。如果考虑整个巴黎大区（Île-de-France），包括周边的郊区，人口则超过1200万。请注意，这些数字会随着时间而有所变化。如果您需要最新的人口统计数据，建议查阅最新的官方发布资料。\n",
      "\n",
      "Q: 这个城市最著名的地标是什么？\n",
      "A: 巴黎最著名的地标无疑是埃菲尔铁塔（Tour Eiffel）。这座铁塔建于1889年，是为了纪念法国大革命一百周年和展示工业技术成就而建造的。它高约324米（包括天线），是巴黎乃至整个法国的象征之一。\n",
      "\n",
      "除了埃菲尔铁塔之外，巴黎还有许多其他著名的地标，例如：\n",
      "- 卢浮宫（Louvre）：世界上最大、最著名的艺术博物馆之一。\n",
      "- 巴黎圣母院（Notre-Dame de Paris）：一座哥特式建筑风格的大教堂，虽然在2019年遭受火灾，但仍然是巴黎的重要标志。\n",
      "- 凯旋门（Arc de Triomphe）：位于香榭丽舍大道的一端，为纪念拿破仑战争胜利而建。\n",
      "- 蒙马特高地（Montmartre）：以其艺术家社区、圣心大教堂（Basilique du Sacré-Cœur）和美丽的风景而闻名。\n",
      "- 塞纳河（Seine River）：流经巴黎市中心，沿岸有许多历史悠久的建筑和桥梁。\n",
      "\n",
      "这些地标不仅代表了巴黎的历史和文化，也是游客们必访的地方。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "prompts = [\"法国首都在哪？\", \"它有多少人口？\", \"这个城市最著名的地标是什么？\"]\n",
    "\n",
    "\n",
    "print(\"单轮回复:\")\n",
    "for prompt in prompts:\n",
    "    print(f\"Q: {prompt}\")\n",
    "    print(f\"A: {llm.invoke(prompt).content}\\n\")\n",
    "\n",
    "# Multi-turn prompts\n",
    "print(\"多轮回复:\")\n",
    "config = {\"configurable\": {\"thread_id\": \"abc456\"}}\n",
    "for prompt in prompts:\n",
    "    print(f\"Q: {prompt}\")\n",
    "    output = app.invoke({\"messages\": [HumanMessage(prompt)]}, config)\n",
    "    print(f\"A: {output['messages'][-1].content}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "prompt",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
